package actions.generate;

import actions.generate.dialog.BindViewPreviewDialog;
import actions.generate.dialog.IDSelectDialog;
import actions.generate.dialog.LayoutChooseDialog;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import utils.CommonUtil;
import utils.FileUtil;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.*;

public class BindViewByIdAction extends AnAction {
    private static final String MESSAGE_TITLE = "BindView 生成提示";

    @Override
    public void actionPerformed(@NotNull AnActionEvent event) {
        EditorImpl editor = FileUtil.getNowEditorFile(event);
        if (editor == null) {
            CommonUtil.showMessage(MESSAGE_TITLE, "当前未打开文件！");
            return;
        }
        List<String> layoutFiles = findLayoutFilesFromEditor(editor);
        if (layoutFiles.isEmpty()) {
            return;
        }

        if (layoutFiles.size() == 1) {
            readLayoutFile(editor, layoutFiles.get(0));
        } else {
            LayoutChooseDialog.show(layout -> readLayoutFile(editor, layout), layoutFiles);
        }
    }

    /**
     * 读取 layoutFileName 的文件，找到所有的 id
     */
    private void readLayoutFile(EditorImpl editor, String layoutFileName) {
        VirtualFile mainFolder = FileUtil.getTargetParent(editor.getVirtualFile(), "main", "src", "app");
        if (mainFolder == null) {
            CommonUtil.showMessage(MESSAGE_TITLE, "当前文件未找到父级main目录！");
            return;
        }
        VirtualFile layoutFile = FileUtil.findFileInPath(mainFolder, layoutFileName + ".xml", "res", "layout");
        if (layoutFile == null) {
            CommonUtil.showMessage(MESSAGE_TITLE, "未找到布局文件!\n\nmainFolder:(" + mainFolder.getPath()
                    + ")\nlayoutFile:(" + layoutFileName + ".xml)");
            return;
        }

        Document document;
        try {
            DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            document = documentBuilder.parse(layoutFile.getPath());
        } catch (SAXException | IOException | ParserConfigurationException e) {
            e.printStackTrace();
            CommonUtil.showMessage(MESSAGE_TITLE, layoutFileName + " 文件解析错误：" + e.getMessage());
            return;
        }
        List<BindViewBeans.BindModel> models = new LinkedList<>();
        collectAllId(models, document);
        IDSelectDialog.show(this::generateBindViewCode, models);
    }

    /**
     * 生成 形如 @BindView(R.id.mainTv1)
     *          TextView mainTv;
     *          的代码
     */
    private void generateBindViewCode(List<BindViewBeans.BindModel> models) {
        StringBuilder stringBuilder = new StringBuilder();
        for (BindViewBeans.BindModel model : models) {
            stringBuilder.append("@BindView(R.id.").append(model.getId()).append(")\n")
                    .append(model.getType()).append(" ").append(model.getPropertyName())
                    .append(";\n");
        }
        BindViewPreviewDialog.show(stringBuilder.toString());
    }

    /**
     * 收集 node 中的所有子节点的 android:id 标识的 节点
     * @param models 会被存储到这个集合中，key 是id， value 是节点类型 如果 TextView
     * @param node 节点
     */
    private void collectAllId(List<BindViewBeans.BindModel> models, Node node) {
        if (node == null) {
            return;
        }
        if (node.hasAttributes()) {
            NamedNodeMap attr = node.getAttributes();
            for (int i = 0, attrLen = attr.getLength(); i < attrLen; i++) {
                Node attrNode = attr.item(i);
                if (attrNode.getNodeType() == Node.ATTRIBUTE_NODE && attrNode.getNodeName().equals("android:id")) {
                    models.add(new BindViewBeans.BindModel(node.getNodeName(),
                            attrNode.getNodeValue().replace("@+id/", "")));
                }
            }
        }
        NodeList childList = node.getChildNodes();
        for (int i = 0; i < childList.getLength(); i++) {
            Node child = childList.item(i);
            if (child != null && child.getNodeType() == Node.ELEMENT_NODE) {
                collectAllId(models, child);
            }
        }
    }

    /**
     * 从当前文件中找到 layout 文件
     *
     * @return 找到的所有 R.layout. 的文件名，如 文件中有 R.layout.activity_main，则返回的List中则会包含一个 activity_main
     */
    private List<String> findLayoutFilesFromEditor(@NotNull EditorImpl editor) {
        List<String> layoutFiles = new LinkedList<>();
        String text = editor.getDocument().getText();
        String findTarget = "R.layout.";
        int len = text.length();
        int fromIndex = 0;
        while (fromIndex >= 0) {
            int ind = text.indexOf(findTarget, fromIndex);
            if (ind < 0) {
                fromIndex = -1;
            } else {
                int p;
                for (p = ind + findTarget.length(); p < len; p++) {
                    char c = text.charAt(p);
                    if (c == ' ' || c == ',' || c == ';') {
                        break;
                    }
                }
                layoutFiles.add(text.substring(ind + findTarget.length(), p));
                fromIndex = p + 1;
            }
        }
        return layoutFiles;
    }
}
